﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
//using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Paloma;

namespace ImageTagger
{
    
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private string GetTagDesc(string tagname)
        {
            foreach (ImageTag it in alltags.tags)
            {
                if (tagname == it.name)
                {
                    if (it.description != it.name)
                        return it.description;
                    else
                        return null;
                }
            }
            return null;
  
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (File.Exists(Application.StartupPath+"\\save") == true) LoadFileList.Visible = true;
            int hltags = 0;
            int lltags = 0;
            lglasscur = new System.Windows.Forms.Cursor(Resource1.Lglass.GetHicon());
            PreviewBox.Cursor = lglasscur;
            alltags = new TagReader();
            alltags.ParseConfigFile(".\\tags.TXT");

            foreach(ImageTag en in alltags.tags)
                if (en.base_tag == alltags.tags[0])
                {
                    TreeOfTags.Nodes.Add(en.name, en.name);
                    hltags++;
                }

            foreach (TreeNode en in TreeOfTags.Nodes)
                {
                    foreach (ImageTag ent in alltags.tags)
                        if (ent.base_tag == null) continue;
                        else
                            if (ent.base_tag.name == en.Name)
                            {
                                en.Nodes.Add(ent.name, ent.name);
                                lltags++;
                            }
                }
            System.Drawing.Font fnt = new Font("Tahoma", 7);
            tagbuttons = new Button[lltags];
            tagbuttonlabels = new Label[hltags];
            int n = 0;
            for (int i = 0; i < hltags; i++)
            {
                tagbuttonlabels[i] = new Label();
                string s = GetTagDesc(TreeOfTags.Nodes[i].Text);
                if (s != null)
                    tagbuttonlabels[i].Text = s;
                else
                    tagbuttonlabels[i].Text = TreeOfTags.Nodes[i].Text;
                tagbuttonlabels[i].Left = 518;
                tagbuttonlabels[i].Top = 40 + i * 24;
                tagbuttonlabels[i].Width = 85;
                tagbuttonlabels[i].Font = fnt;
                tagbuttonlabels[i].Height = 20;
                this.Controls.Add(tagbuttonlabels[i]);
                tagbuttonlabels[i].Visible = true;

                for (int j = 0; j < TreeOfTags.Nodes[i].Nodes.Count; j++)
                {
                 tagbuttons[n] = new Button();
                 tagbuttons[n].Text = TreeOfTags.Nodes[i].Nodes[j].Text;
                foreach (ImageTag it in alltags.tags)
                {
                    if (it.name == TreeOfTags.Nodes[i].Nodes[j].Text)
                    {
                        if (it.description != it.name)
                            tagbuttons[n].Tag = it.description;
                        break;
                        }
                }
                 ;
                 tagbuttons[n].Left = 600 + 60 * (j);
                 tagbuttons[n].Top = 40 + i * 24;
                 tagbuttons[n].Width = 55;
                 tagbuttons[n].Font = fnt;
                 tagbuttons[n].Height = 20;
                 tagbuttons[n].Click += Tagbuttons_Click;
                 this.Controls.Add(tagbuttons[n]);
                 tagbuttons[n].BringToFront();
                 tagbuttons[n].Visible = true;
                 tagbuttons[n].Image = Resource1.OffIndicator;
                 tagbuttons[n].ImageAlign = ContentAlignment.MiddleRight;
                 tagbuttons[n].TextAlign = ContentAlignment.MiddleLeft;
                 n++;
                }

            }
            foreach (Control c in this.Controls)
                if (c.Tag != null)
                    if (c.Tag is string)
                         c.MouseMove += new MouseEventHandler(MaybeHisComponentHasHelp_MouseMove);
        }

        private void Tagbuttons_Click(object sender, EventArgs e)
        {
            foreach (ImageTag t in alltags.tags)
            {
                if (t.name == ((Button)sender).Text)
                {
                    t.used = !t.used;
                    if (t.used)
                        ((Button)sender).Image = Resource1.OnIndicator;
                    else
                        ((Button)sender).Image = Resource1.OffIndicator;
                    break;
                }  
            }
            
            GenerateNewFileName();
       //     ResultName.Text = ((Button)sender).Text + " " + ResultName.Text;
        }

        private void ViewChanger_Click(object sender, EventArgs e)
        {
            if (TreeOfTags.Visible == true)
            {
                TreeOfTags.Visible = false;
                    foreach (Button b in tagbuttons)
                        if (b != null)
                            b.Visible = true;
                    foreach (Label b in tagbuttonlabels)
                        if (b != null)
                            b.Visible = true;
            }
            else
            {
                TreeOfTags.Visible = true;
                    foreach (Button b in tagbuttons)
                        if (b != null)
                            b.Visible = false;
                    foreach (Label b in tagbuttonlabels)
                        if (b != null)
                            b.Visible = false;
            }
        }

        private void WorkFolderSelect_Click(object sender, EventArgs e)
        {
            if (imgfiles == null)
                imgfiles = new List<string>();
            else
                imgfiles.Clear();
            ImageIndentifier ii = new ImageIndentifier();
            DirectoryInfo rootdir;
            DirectoryInfo[] dirs;
            FileInfo file;
            string fn;
            if (WorkFolderDialog.ShowDialog() == DialogResult.OK)
            {
                file = new FileInfo(WorkFolderDialog.FileName);
                fn = file.Directory.FullName;
            }
            else
                return;
            rootdir = new DirectoryInfo(fn);
            dirs =  rootdir.GetDirectories("*",System.IO.SearchOption.AllDirectories);
            DirectoryProgress.Maximum = dirs.Length;
            DirectoryProgress.Visible = true;
            Application.DoEvents();
            foreach (DirectoryInfo d in dirs)
            {
                foreach (FileInfo f in d.GetFiles("*",System.IO.SearchOption.TopDirectoryOnly))
                {
                    if (ii.IsImage(f.FullName) == true)
                    {
                        imgfiles.Add(f.FullName);
                    }
                }
                DirectoryProgress.Value = DirectoryProgress.Value + 1;
                Application.DoEvents();
            }
            foreach (FileInfo f in rootdir.GetFiles("*", System.IO.SearchOption.TopDirectoryOnly))
            {
                if (ii.IsImage(f.FullName) == true)
                {
                    imgfiles.Add(f.FullName);
                }
            }
            ProgressLabel.Text = imgfiles.Count.ToString();
            DirectoryProgress.Visible = false;
            ReadImage(imgfiles[0]);
            PreviewBox.Refresh();
            if (destpath != "") SaveListButton.Visible = true;
            
        }

        private bool ReadImage(string filename)
        {
            Image tmp = null;
            try
            {
                tmp = new Bitmap(filename);
            }
            catch (Exception)
            {
                ImageIndentifier ii = new ImageIndentifier();
                if (ii.CheckTarga(filename))
                {
                    TargaImage ti = new TargaImage(filename);
                    mainimage = new Bitmap(ti.Image);
                }
                else
                {
                    tmp = new Bitmap(Resource1.Sorry);
                }
            }

            mainimage = new Bitmap(tmp.Width, tmp.Height,System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            Graphics gr = Graphics.FromImage(mainimage);
            Rectangle r = new Rectangle(0,0,tmp.Width,tmp.Height);
            gr.DrawImage(tmp,r,r,System.Drawing.GraphicsUnit.Pixel);
            scaledimage = new Bitmap(mainimage,new Size(mainimage.Size.Width * 2,mainimage.Size.Height * 2));
            FileInfo fi = new FileInfo(filename);
            //ResultName.Text = fi.Name;
            return true;
        }

        private void PreviewBox_Click(object sender, EventArgs e)
        {
            scalemode = !scalemode;
            PreviewBox.Cursor = lglasscur;
        }

        private void PreviewBox_Paint(object sender, PaintEventArgs e)
        {
            PreviewBox.Cursor = lglasscur;
            if (scalemode)
            {
                if (scaledimage == null) return;
                PreviewBox.Image = scaledimage;
            }
            else
            {
                if (mainimage == null) return;
                PreviewBox.Image = mainimage;
            }
        }

        private void SaveListButton_Click(object sender, EventArgs e)
        {
            
            FileStream fs = new FileStream(Application.StartupPath+"\\save",System.IO.FileMode.Create);
            BinaryWriter bw = new BinaryWriter(fs,System.Text.Encoding.UTF8);
            bw.Write(destpath);
            bw.Write(imgfiles.Count);
            foreach (string s in imgfiles)
                bw.Write(s);
            bw.Close();
            fs.Close();
            LoadFileList.Visible = true;


        }

        private void ResultFolderSelect_Click(object sender, EventArgs e)
        {
            FileInfo file;
            if (ResultFolderDialog.ShowDialog() == DialogResult.OK)
            {
                file = new FileInfo(ResultFolderDialog.FileName);
                destpath = file.Directory.FullName;
            }
            if (imgfiles != null)
                if (imgfiles.Count != 0)
                    SaveListButton.Visible = true;

        }

        private void LoadFileList_Click(object sender, EventArgs e)
        {
            FileStream fs = new FileStream(".\\save", System.IO.FileMode.Open);
            BinaryReader bw = new BinaryReader(fs, System.Text.Encoding.UTF8);
            destpath = bw.ReadString();
            int count = bw.ReadInt32();
            string tmp;
            if (imgfiles != null)
                imgfiles.Clear();
            else
                imgfiles = new List<string>();
            for (int i = 0; i < count; i++)
            {
                tmp = bw.ReadString();
                imgfiles.Add(tmp);
            }
            SaveListButton.Visible = true;
            ReadImage(imgfiles[0]);
            ProgressLabel.Text = imgfiles.Count.ToString();
            PreviewBox.Refresh();
            GenerateNewFileName();
        }

        private void PrepareNextFile()
        {
            foreach (Button b in tagbuttons)
                b.Image = Resource1.OffIndicator;
            imgfiles.RemoveAt(0);
            ProgressLabel.Text = imgfiles.Count.ToString();
            if (imgfiles.Count == 0) return;
            ReadImage(imgfiles[0]);
            PreviewBox.Refresh();
            foreach (ImageTag t in alltags.tags)
            {
                t.prevused = t.used;
                t.used = false;
            }
            if (ColorAppraiserMode)
                AppraiseImage(mainimage);
        }

        private void GenerateNewFileName()
        {
            if (imgfiles == null) return;
            if (imgfiles[0] == null) return;
            StringBuilder r = new StringBuilder(200);
            foreach (ImageTag t in alltags.tags)
            {
                if (t.used)
                {
                    r.Append(t.name);
                    r.Append(" ");
                }
            }
            
            FileInfo fi = new FileInfo(imgfiles[0]);
            ResultName.Text = r.ToString() + fi.Name;
            
        }

        private void ProcessFile_Click(object sender, EventArgs e)
        {
            if (imgfiles.Count == 0) return;
            FileInfo old = new FileInfo(imgfiles[0]);
            old.CopyTo(destpath + "\\" + ResultName.Text,true);
            PrepareNextFile();

        }

        private void Skip_Click(object sender, EventArgs e)
        {
            if (imgfiles.Count == 0) return;
            PrepareNextFile();

        }

        private void PreviousSetButton_Click(object sender, EventArgs e)
        {
            foreach (ImageTag t in alltags.tags) 
            {
                t.used = t.prevused;
                foreach (Button b in tagbuttons)
                {
                    if (t.name == b.Text)
                    {
                        if (t.used)
                            b.Image = Resource1.OnIndicator;
                        else
                            b.Image = Resource1.OffIndicator;
                        break;
                    }
                }
            }
            GenerateNewFileName();
        }

        private void ForawrdButton_Click(object sender, EventArgs e)
        {
            if (imgfiles.Count == 0) return;
            if (previewimgn+1 >= imgfiles.Count) return;
            previewimgn++;
            BackwardButton.Visible = true;
            BeginButton.Visible = true;
            ReadImage(imgfiles[previewimgn]);
            PreviewBox.Refresh();
        }

        private void BackwardButton_Click(object sender, EventArgs e)
        {
            if (previewimgn == 0) return;
            previewimgn--;
            if (previewimgn == 0)
            {
                BackwardButton.Visible = false;
                BeginButton.Visible = false;
            }
            ReadImage(imgfiles[previewimgn]);
            PreviewBox.Refresh();
        }

        private void BeginButton_Click(object sender, EventArgs e)
        {
                if (previewimgn == 0) return;
                previewimgn=0;
                BackwardButton.Visible = false;
                BeginButton.Visible = false;
                ReadImage(imgfiles[0]);
                PreviewBox.Refresh();

        }


        private void MaybeHisComponentHasHelp_MouseMove(object sender, MouseEventArgs e)
        {
            Control c = (Control)sender;
            if (c != null)
            if (c.Tag != null)
                if (c.Tag is string)
                {
                    statusStrip1.Items[0].Text = (string)c.Tag;
                    return;
                }
            statusStrip1.Items[0].Text = "";
        }



        private void MainForm_MouseMove(object sender, MouseEventArgs e)
        {
            statusStrip1.Items[0].Text = "";
        }

        private void AppraiseImage(Bitmap img)
        {
            IntPtr p;
            Color c;
            System.Collections.Generic.Dictionary<string, float> dictonary = new Dictionary<string, float>();
            if (img == null)
                return;
            float t;
            foreach (ImageColourTag ict in alltags.colours)
            {
                if (dictonary.ContainsKey(ict.It.name) == false)
                    dictonary.Add(ict.It.name, 0);

            }


            System.Drawing.Imaging.BitmapData data = new System.Drawing.Imaging.BitmapData();
            img.LockBits(new Rectangle(new Point(0, 0), img.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, img.PixelFormat, data);
            p = data.Scan0;
            int bytes = Math.Abs(data.Stride) * data.Height;
            Int32[] rgbValues = new int[bytes / 4];
            System.Runtime.InteropServices.Marshal.Copy(p, rgbValues, 0, bytes / 4);
            int sz = data.Height * data.Width;
            int pos = 0;
            for (int i = 0; i < data.Height; i++)
            {
                for (int j = 0; j < data.Width; j++)
                {
                    c = System.Drawing.Color.FromArgb(rgbValues[j + pos]);
                    HSVObject h = RGB2HSV(c.R, c.G, c.B);
                    int H = h.H;
                    int S = h.S;
                    int V = h.V;
                    foreach (ImageColourTag ict in alltags.colours)
                    {
                        t = ict.AppraisePixel(H, S, V);
                        if (t > 0)
                            dictonary[ict.It.name] += t;
                    }

                }
                pos += data.Width;
            }
            foreach (System.Collections.Generic.KeyValuePair<string, float> delem in dictonary)
            {
                float Threshold = alltags.GetColourTag(delem.Key).Threshold;
                Threshold *= sz;
                Threshold /= 100;
                if (delem.Value > Threshold)
                    foreach (Button b in tagbuttons)
                    {
                        if (b.Text == delem.Key)
                            b.Image = Resource1.YellowIndicator;
                    }
                else
                    foreach (Button b in tagbuttons)
                    {
                        if (b.Text == delem.Key)
                          foreach(ImageTag it in alltags.tags)
                              if (it.name == delem.Key)
                                  if (it.used)
                                      b.Image = Resource1.OnIndicator;
                                  else
                                      b.Image = Resource1.OffIndicator;
                    }

            }

            img.UnlockBits(data);

        }

        private void ColorAppraiseButton_Click(object sender, EventArgs e)
        {
            ColorAppraiserMode = !ColorAppraiserMode;
            if (ColorAppraiserMode)
            {
                AppraiseImage(mainimage);
                ColorAppraiseButton.Image = Resource1.YellowIndicator;
            }
            else
                ColorAppraiseButton.Image = Resource1.OffIndicator;
        }

        
            private HSVObject RGB2HSV(int red, int green, int blue)
        {
            float H, S, V;

            float r = (red / 255.0f);
            float g = (green / 255.0f);
            float b = (blue / 255.0f);
            float min = Math.Min(Math.Min(r, g), b);
            float max = Math.Max(Math.Max(r, g), b);
            float delta = max - min;

            V = max;

            if (delta == 0)
            {
                H = 0;
                S = 0;
            }
            else
            {
                S = delta / max;

                float dR = ((((max - r) / 6) + (delta / 2)) / delta);
                float dG = ((((max - g) / 6) + (delta / 2)) / delta);
                float dB = ((((max - b) / 6) + (delta / 2)) / delta);

                if (r == max)
                    H = (float) (dB - dG);
                else if (g == max)
                    H = (float)((1.0f / 3) + dR - dB);
                else
                    H = (float)((2.0f / 3) + dG - dR);

                if (H < 0)
                    H += 1;

                if (H > 1)
                    H -= 1;
            }

            return new HSVObject(H, S, V);
        }

            private void AboutButton_Click(object sender, EventArgs e)
            {
                if (AboutForm == null) AboutForm = new About();
                AboutForm.ShowDialog();
            }

            private void statusStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
            {

            }

    }


    public class ImageIndentifier
    {
        public bool IsImage(string path)
        {
            byte[] buf = new byte[26];
            char[] targach;
            Stream sr = new FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            BinaryReader br = new BinaryReader(sr, System.Text.Encoding.ASCII);
            br.Read(buf, 0, 10);
            if ((buf[0] == 'B') && (buf[1] == 'M')) return true; // Windows BITMAP
            if ((buf[0] == 0xff) && (buf[1] == 0xd8)) return true; // Jpeg
            if ((buf[0] == 0x47) && (buf[1] == 0x49) && (buf[2] == 0x46) && (buf[3] == 0x38) && (buf[4] == 0x39) && (buf[5] == 0x61)) return true; // GIF
            if ((buf[0] == 0x89) && (buf[1] == 0x50) && (buf[2] == 0x4e) && (buf[3] == 0x47) && (buf[4] == 0x0d) && (buf[5] == 0x0a) && (buf[6] == 0x1a) && (buf[7] == 0x0a)) return true; // PNG
            targach = new Char[26];
            br.BaseStream.Seek(-26, System.IO.SeekOrigin.End);
            targach = br.ReadChars(26);
            string targa = new string(targach, 8, 17);
            if (targa == "TRUEVISION-XFILE.") return true; // TRUEVISION Targa
            if (path.Substring(path.Length - 3, 3).ToLower() == "pcx") return true; //old as dinoshit pcx? Baybe...

            return false;
        }
        public bool CheckTarga(string path)
        {
            char[] targach;
            Stream sr = new FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            BinaryReader br = new BinaryReader(sr, System.Text.Encoding.ASCII);
            targach = new Char[26];
            br.BaseStream.Seek(-26, System.IO.SeekOrigin.End);
            targach = br.ReadChars(26);
            string targa = new string(targach, 8, 17);
            if (targa == "TRUEVISION-XFILE.") return true; // TRUEVISION Targa
            return false;
        }
    }
 

    class HSVObject
    {
        public int H;
        public int S;
        public int V;

        public HSVObject(float H, float S, float V)
        {
            this.H = (int)Math.Round(H * 360);
            this.S = (int)Math.Round(S * 100);
            this.V = (int)Math.Round(V * 100);
        }
    }
}
